package com.logicbus.backend.message;

import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;

import com.anysoft.util.PropertiesConstants;
import com.anysoft.util.compress.Compressor;
import com.anysoft.util.compress.compressor.GZIP;
import com.anysoft.webloader.HttpClientTool;
import com.logicbus.backend.message.tools.JsonFactory;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.anysoft.util.IOTools;
import com.anysoft.util.Settings;
import com.logicbus.backend.Context;
import com.logicbus.backend.server.http.HttpContext;

import javax.servlet.http.HttpServletResponse;

/**
 * JsonRawMessage
 * @author yyduan
 * 
 * @since 1.6.11.12
 *
 * @version 1.6.13.21 [20201021 duanyy] <br>
 * - 支持gzip压缩 <br>
 */
public class JsonRawMessage implements Message {
	protected static final Logger logger = LoggerFactory.getLogger(JsonMessage.class);
	protected static JsonFactory jsonFactory = null;
	protected static String formContentType = "application/x-www-form-urlencoded";
	private static Compressor gzipCompressor = new GZIP();
	private static boolean gzipSupport = false;
	private static HttpClientTool clientTool = null;

	static {
		gzipSupport = PropertiesConstants.getBoolean(Settings.get(),"http.json.gzip",gzipSupport);
		jsonFactory = Settings.getToolkit(JsonFactory.class);
		formContentType = Settings.get().GetValue("http.formContentType",
				"application/x-www-form-urlencoded");
		clientTool = Settings.getToolkit(HttpClientTool.class);
	}
	
	private String contentType = "application/json;charset=utf-8";

	private boolean isGzipEnable(Context ctx,String header){
		if (!gzipSupport) {
			return false;
		}
		String gzip = ctx.getRequestHeader(header);
		return StringUtils.isNotEmpty(gzip)?gzip.equalsIgnoreCase("gzip"):false;
	}

	/**
	 * Json结构的根节点
	 */
	protected Map<String,Object> root = null;	
	
	private long contentLength = 0;
	
	@SuppressWarnings("unchecked")
	@Override
	public void init(Context ctx) {
		boolean gzipEnable = isGzipEnable(ctx,"Content-Encoding");
		String data = null;
		{
			byte [] inputData = ctx.getRequestRaw();
			if (inputData != null){
				try {
					if (gzipEnable && inputData.length > 0){
						inputData = gzipCompressor.decompress(inputData);
					}
					data = new String(inputData,ctx.getEncoding());
				}catch (Exception ex){
					
				}
			}
		}
		
		if (data == null){
			//当客户端通过form来post的时候，Message不去读取输入流。
			String _contentType = ctx.getRequestContentType();
			if (_contentType == null || !_contentType.startsWith(formContentType)){
				InputStream in = null;
				try {
					in = ctx.getInputStream();
					if (gzipEnable && in.available() > 0){
						in = gzipCompressor.getInputStream(in);
					}
					data = Context.readFromInputStream(in, ctx.getEncoding());					
				}catch (Exception ex){
					logger.error("Error when reading data from inputstream",ex);
				}finally{
					IOTools.close(in);
				}
			}
		}
		
		if (data != null && data.length() > 0){
			contentLength += data.getBytes().length;
			Object rootObj = jsonFactory.fromJsonString(data);
			if (rootObj instanceof Map){
				root = (Map<String,Object>)rootObj;
			}
		}
		if (root == null){
			root = new HashMap<String,Object>();
		}
		
		contentType = "application/json;charset=" + ctx.getEncoding();
	}

	@Override
	public void finish(Context ctx,boolean closeStream) {
		OutputStream out = null;
		try {
			out = ctx.getOutputStream();
			String code = ctx.getReturnCode();
			if (!code.equals("core.ok")){
				if (ctx instanceof HttpContext){
					HttpContext httpContext = (HttpContext)ctx;
					clientTool.sendError(httpContext.getResponse(),HttpServletResponse.SC_NOT_FOUND, ctx.getReturnCode() + ":" + ctx.getReason());
				}
			}
		}catch (Exception ex){
			logger.error("Error when writing data to outputstream",ex);
		}finally{
			if (closeStream) {
				IOTools.close(out);
			}
		}
	}	

	/**
	 * 获取JSON结构的根节点
	 * 
	 * @return JSON结构的根节点
	 */
	public Map<String,Object> getRoot(){
		return root;
	}

	@Override
	public String toString(){
		return jsonFactory.toJsonString(root);
	}
		
	@Override
	public String getContentType() {
		return contentType;
	}

	@Override
	public long getContentLength() {
		return contentLength;
	}

}
